package code;

import java.io.FileWriter;
import java.util.Random;

import weka.classifiers.Classifier;
import weka.classifiers.Evaluation;
import weka.classifiers.functions.SMO;
import weka.classifiers.functions.supportVector.Kernel;
import weka.classifiers.functions.supportVector.PolyKernel;
import weka.classifiers.functions.supportVector.RBFKernel;
import weka.core.Instances;
//import weka.core.Utils;
import weka.classifiers.meta.CVParameterSelection;


public class ScanParamsAlgorithm {
	
	//ATTRIBUTES
	private String[] path;
	
	public ScanParamsAlgorithm(String[] args) {
		path = args;
	}

	public void execute() throws Exception{
		//LOAD DATA FILE
		Instances data = DataFiles.getInstance().loadDataFile(path[0]);
		Instances dataTest = DataFiles.getInstance().loadDataFile(path[1]);
			
		//NORMALIZE THE ATTRIBUTES: APPLY NORMALIZE FILTER 
		data = Preproceso.getInstance().normalizar(data);		
		dataTest = Preproceso.getInstance().normalizar(dataTest);

		//LOAD WRITER FILE
		FileWriter ficheroGuardado = DataFiles.getInstance().loadWriterFile(path[3]);
		
		//TRAINING
		trainAndTest(data, dataTest, ficheroGuardado);
				
	}

	private void trainAndTest(Instances data, Instances dataTest, FileWriter ficheroGuardado) throws Exception {
		//CHOOSE SVM AS ESTIMATOR 
		SMO estimador = new SMO(); 		
		
		////////////TRAIN\\\\\\\\\\\\\\\				
		Evaluation evaluator = new Evaluation(data);
		//LOAD GIRDSEARCH
		CVParameterSelection gridSearch = new CVParameterSelection(); 		
		//BARRIDO Y SELECCION DE PARAMETROS
		aplicarPolyKernel(estimador, gridSearch, evaluator, data);
		
		/*
		gridSearch = new CVParameterSelection(); 
		Evaluation evaluator = new Evaluation(data);		
		//BARRIDO Y SELECCION DE PARAMETROS
		aplicarRBFKernel(estimador, gridSearch, evaluator, data);	
		*/

		////////////TEST\\\\\\\\\\\\\\\
		
		//EVALUATE TEST
        test(estimador, evaluator, data, dataTest, ficheroGuardado); 			    
	}

	private void test(SMO estimador, Evaluation evaluator, Instances data, Instances dataTest, FileWriter ficheroGuardado) throws Exception {
	    
		estimador.buildClassifier(data);	         

	    //LET THE MODEL PREDICT THE CLASS FOR EACH INSTANCE IN THE TEST SET
	    evaluator.evaluateModel(estimador, dataTest);
	  
	    //SAVE DATA IN FILE
	    ficheroGuardado.write("Numero de instancias: ");
	    ficheroGuardado.write(dataTest.numInstances()+"\n");

	    String valorNominal;
	    for (int i = 0; i < dataTest.numInstances(); i++) {
	    	//EVALUATE THE CLASSIFIER ON A SINGLE INSTANCE AND RECORD THE PREDICTION
	    	if (evaluator.evaluateModelOnceAndRecordPrediction((Classifier)estimador, dataTest.instance(i))== 1.0){
	    		valorNominal="no";
	    	}else{
	    		valorNominal="yes";
	    	}
	    ficheroGuardado.write("Evaluador: "+valorNominal+"\n");
	    }
		//CLOSE THE FILE
		ficheroGuardado.close();
	}

	private void aplicarPolyKernel(SMO estimador, CVParameterSelection gridSearch, Evaluation evaluator, Instances data) throws Exception {
		System.out.println("--SVM:PolyKernel--");
		
		Kernel k2 = new PolyKernel();
		//CHOOSE THE KERNEL, POLYKERNEL
		estimador.setKernel(k2);
		//CHOOSE CLASSIFIER 
		gridSearch.setClassifier(estimador); 
		//ADJUST PARAMETERS - C AND EXPONENT
		gridSearch.addCVParameter("C 0.1 5.0 20");
		gridSearch.addCVParameter("E 1.0 2.0 2");
		//LOAD DATA - CLASSIFIER
		gridSearch.buildClassifier(data);
		
		/*
		Classifier c1 = gridSearch.getClassifier();
		System.out.println(c1.toString());
		System.out.println(Utils.joinOptions(gridSearch.getBestClassifierOptions()));
		*/
		
		//VALIDATE WITH 10-FOLD CROSS VALIDATION
		evaluator.crossValidateModel(estimador, data, 10, new Random(10));
		System.out.println("correct: "+evaluator.correct());
		System.out.println("fmeasure: "+evaluator.fMeasure(1));
		
	}

	private void aplicarRBFKernel(SMO estimador, CVParameterSelection gridSearch, Evaluation evaluator, Instances data) throws Exception {
		System.out.println("--SVM:RBFKernel--");
		
		Kernel k1 = new RBFKernel();
		//CHOOSE THE KERNEL, RBFKERNEL
		estimador.setKernel(k1);		
		//CHOOSE CLASSIFIER 
		gridSearch.setClassifier(estimador); 		
		//ADJUST PARAMETERS - C AND GAMMA
		gridSearch.addCVParameter("C 10.0 30.0 5");
		gridSearch.addCVParameter("G 0.0001 20.0 5");
		//LOAD DATA - CLASSIFIER
		gridSearch.buildClassifier(data);
		
		/*
		Classifier c2 = gridSearch.getClassifier();
		System.out.println(c2.toString());
		System.out.println(Utils.joinOptions(gridSearch.getBestClassifierOptions()));
		*/
		
		//VALIDATE WITH 10-FOLD CROSS VALIDATION
		evaluator.crossValidateModel(estimador, data, 10, new Random(10));
		System.out.println("correct: "+evaluator.correct());	
		System.out.println("fmeasure: "+evaluator.fMeasure(1));

	}		 
}
